#pragma once

#include <iostream>
#include <functional>
#include <vector>
#include "Sock.hpp"
#include "Util.hpp"
#include "Log.hpp"

using func_t = std::function<std::string(std::string &)>;

class ns_server;

class ThreadData
{
public:
    ThreadData(int sock, std::string clientIp, uint16_t clientPort, ns_server *server)
        : _sock(sock), _clientIp(clientIp), _clientPort(clientPort), _server(server)
    {
    }

    ~ThreadData()
    {
    }

public:
    int _sock;
    std::string _clientIp;
    uint16_t _clientPort;
    ns_server *_server;
};

class ns_server
{
public:
    ns_server(uint16_t serverport, func_t func)
        : _serverPort(serverport), _func(func)
    {
    }

    void InitServer()
    {
        _listenSock.Socket();
        _listenSock.Bind(_serverPort);
        _listenSock.Listen();
    }

    void start()
    {
        while (true)
        {
            std::string clientIp;
            uint16_t clientPort;
            int sock = _listenSock.Accept(&clientIp, &clientPort);
            if (sock > 0)
            {
                LogMessage(Debug, "%s-%d accept success", clientIp.c_str(), clientPort);
            }

            ThreadData *data = new ThreadData(sock, clientIp, clientPort, this);
            pthread_t tid;
            pthread_create(&tid, nullptr, ThreadRoutine, data);
        }
    }

    void HandlerHttpRequest(int sock,std::string clientIp,uint16_t clientPort)
    {
        char buffer[1024];
        int n = recv(sock,buffer,sizeof(buffer) - 1,0);
        if(n == -1)
            LogMessage(Error,"recv fail");
        else if(n == 0)
            LogMessage(Debug,"%s-%d exit",clientIp.c_str(),clientPort);
        else
        {
            buffer[n] = '\0';
            std::string request = buffer;        
            std::string result = _func(request);
            send(sock,result.c_str(),result.size(),0);
        }
    }

    static void *ThreadRoutine(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *data = static_cast<ThreadData *>(args);
        data->_server->HandlerHttpRequest(data->_sock,data->_clientIp,data->_clientPort);
        LogMessage(Debug, "%s-%d exit", data->_clientIp.c_str(), data->_clientPort);
        close(data->_sock);
        delete data;
        return nullptr;
    }

private:
    Sock _listenSock;
    uint16_t _serverPort;
    func_t _func;
};
